package pl.un4giv3n.mightvsmagic.entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Transient;


/**
 * @author andrzejewskia
 * user entity
 */
@NamedQueries({
	@NamedQuery(name ="find.all.unblocked.users", query = "select u from User u where u.userType != 2 and u.blocked = false"),
	@NamedQuery(name ="find.all.blocked.users", query = "select u from User u where u.userType != 2 and u.blocked = true"),
	@NamedQuery(name ="find.all.users", query = "select u from User u where u.userType != 2"),
	@NamedQuery(name ="find.attackable.users.with.type", query = "select u from User u where u.userType != 2 and u.blocked = false and lastFightTime < :time and u.userType = :type"),
	@NamedQuery(name ="find.attackable.users", query = "select u from User u where u.userType != 2 and u.blocked = false and lastFightTime < :time"),
	@NamedQuery(name ="find.admins", query = "select u from User u where u.userType = 2"),
	@NamedQuery(name="find.user.by.email", query="select u from User u where u.email=:email and u.blocked = false"),
	@NamedQuery(name="find.user.by.login", query="select u from User u where u.login=:login and u.blocked = false"),
	@NamedQuery(name="find.user.pending.clan", query="select u from User u where u.clanAcceptancePending=true and u.clan.id = :clanId"),
	@NamedQuery(name="admin.find.user.by.login", query="select u from User u where u.login=:login"),
	@NamedQuery(name="admin.find.user.by.email", query="select u from User u where u.email=:email")
})
@Entity
public class User implements Serializable {
	private static final long serialVersionUID = 1L;
	
	/**
	 * id
	 */
	private Long id;
	/**
	 * user login - this is in fact a db PK
	 */
	private String login;
	/**
	 * user email
	 */
	private String email;
	/**
	 * user gold
	 */
	private long gold = 50;
	/**
	 * dragonTeeth - waluta kupowana smsami
	 */
	private long dragonTeeth;
	/**
	 * user fight exp
	 */
	private long fightExp = 0;
	/**
	 * user magic exp
	 */
	private long magicExp = 0;
	/**
	 * user passwd
	 */
	private String password;
	/**
	 * time of last fight performed by the user
	 */
	private long lastFightTime;
	/**
	 * user attributes (strenght,stamina etc)
	 */
	private long strenght;
	private long stamina;
	private long mana;
	private long attack;
	private long parry;
	private long life;
	private long speed = 10;
	/**
	 * user items
	 */
	private List<Item> items = new ArrayList<Item>();
	/**
	 * last action performed by user
	 */
	@Embedded
	private Action currentAction;
	/**
	 * is premium user
	 */
	private long premiumEndTime;
	/**
	 * user hitpoints
	 */
	private double hp;
	@Enumerated(EnumType.STRING)
	private UserType userType;
	
	private Set<SpecialSkill> skills;
	
	private boolean blocked = false;
	private Date blockedUntil;
	private String blockReason;
	private Clan clan;
	private boolean clanAcceptancePending;
	private boolean clanAdmin;
	private boolean clanMod;
	private String clanRank;
	
	@SuppressWarnings("unused")
	private User() {
		super();
	}

	public User(String login, String passwd, String email, UserType userType) {
		super();
		this.login = login;
		this.password = passwd;
		this.email = email;
		this.strenght = 5;
		this.attack = 5;
		this.parry = 5;
		this.life = 5;
		currentAction = Action.NO_ACTION;
		hp = life * 10;
		if(userType == UserType.KNIGHT){
			this.stamina = 15;
			this.mana = 0;
			fightExp = 5;
		}else if(userType == UserType.MAGE){
			this.stamina = 0;
			this.mana = 15;
			magicExp = 5;
		}
		this.userType = userType;
		this.skills = new HashSet<SpecialSkill>();
	}
	@Id
	@GeneratedValue
	public Long getId() {
		return id;
	}

	public String getLogin() {
		return login;
	}

	public void setLogin(String name) {
		this.login = name;
	}

	@OneToMany(fetch=FetchType.EAGER, cascade={CascadeType.ALL})
	public List<Item> getItems() {
		return items;
	}

	public void setItems(List<Item> items) {
		this.items = items;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	void setId(Long id) {
		this.id = id;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public long getGold() {
		return gold;
	}

	void setGold(long gold) {
		this.gold = gold;
	}

	public long getFightExp() {
		return fightExp;
	}

	void setFightExp(long fightExp) {
		this.fightExp = fightExp;
	}

	public long getMagicExp() {
		return magicExp;
	}

	void setMagicExp(long magicExp) {
		this.magicExp = magicExp;
	}

	public Action getCurrentAction() {
		return currentAction;
	}

	public void setCurrentAction(Action currentAction) {
		this.currentAction = currentAction;
	}
	@Transient
	public boolean isPremium() {
		return premiumEndTime == 0 ? false : premiumEndTime > System.currentTimeMillis();
	}

	public long getLastFightTime() {
		return lastFightTime;
	}

	public void setLastFightTime(long lastFightTime) {
		this.lastFightTime = lastFightTime;
	}

	public double getHp() {
		return hp;
	}

	public void setHp(double hp) {
		this.hp = hp;
	}

	public UserType getUserType() {
		return userType;
	}

	public void setUserType(UserType userType) {
		this.userType = userType;
	}

	public long getStrenght() {
		return strenght;
	}

	public void setStrenght(long strenght) {
		this.strenght = strenght;
	}

	public long getStamina() {
		return stamina;
	}

	public void setStamina(long stamina) {
		this.stamina = stamina;
	}

	public long getMana() {
		return mana;
	}

	public void setMana(long mana) {
		this.mana = mana;
	}

	public long getAttack() {
		return attack;
	}

	public void setAttack(long attack) {
		this.attack = attack;
	}

	public long getParry() {
		return parry;
	}

	public void setParry(long parry) {
		this.parry = parry;
	}

	public long getLife() {
		return life;
	}

	public void setLife(long life) {
		this.life = life;
	}

	public long getPremiumEndTime() {
		return premiumEndTime;
	}

	public void setPremiumEndTime(long premiumEndTime) {
		this.premiumEndTime = premiumEndTime;
	}

	public long getDragonTeeth() {
		return dragonTeeth;
	}

	public void setDragonTeeth(long dragonTeeth) {
		this.dragonTeeth = dragonTeeth;
	}
	@OneToMany(cascade=CascadeType.ALL)
	public Set<SpecialSkill> getSkills() {
		return skills;
	}

	public void setSkills(Set<SpecialSkill> skills) {
		this.skills = skills;
	}

	public boolean isBlocked() {
		return blocked;
	}

	public void setBlocked(boolean blocked) {
		this.blocked = blocked;
	}

	@ManyToOne(targetEntity=Clan.class)
	public Clan getClan() {
		return clan;
	}
	public void setClan(Clan clan) {
		this.clan = clan;
	}

	public boolean isClanAcceptancePending() {
		return clanAcceptancePending;
	}

	public void setClanAcceptancePending(boolean clanAcceptancePending) {
		this.clanAcceptancePending = clanAcceptancePending;
	}

	public long getSpeed() {
		return speed;
	}
	@Transient
	public long getCalculatedSpeed() {
		long baseSpeed = speed;
		if(userType == UserType.MAGE){
			baseSpeed += magicExp/750;
		}else if(userType == UserType.KNIGHT){
			baseSpeed += fightExp/750;
		}
		return baseSpeed;
	}

	public void setSpeed(long speed) {
		this.speed = speed;
	}

	@Override
	public String toString() {
		return "Id="+id+", login="+login;
	}

	public Date getBlockedUntil() {
		return blockedUntil;
	}

	public void setBlockedUntil(Date blockedUntil) {
		this.blockedUntil = blockedUntil;
	}

	public String getBlockReason() {
		return blockReason;
	}

	public void setBlockReason(String blockReason) {
		this.blockReason = blockReason;
	}

	public boolean isClanAdmin() {
		return clanAdmin;
	}

	public void setClanAdmin(boolean clanAdmin) {
		this.clanAdmin = clanAdmin;
	}

	public boolean isClanMod() {
		return clanMod;
	}

	public void setClanMod(boolean clanMod) {
		this.clanMod = clanMod;
	}

	public String getClanRank() {
		return clanRank;
	}

	public void setClanRank(String clanRank) {
		this.clanRank = clanRank;
	}
	/**
	 * set hp to max value
	 */
	@Transient
	public void resetHp(){
		hp = life * 10;
	}
	@Transient
	public void addGold(long gold){
		this.gold +=gold;
	}
	@Transient
	public void removeGold(long gold){
		this.gold -=gold;
	}
	@Transient
	public void addFightExp(long fightExp){
		this.fightExp +=fightExp;
	}
	@Transient
	public void addMagicExp(long magicExp){
		this.magicExp +=magicExp;
	}
}
